<template>
  <transition name="kc-zoom-in-down">
    <div class="kc-datepicker-main kc-datepicker-popup" } :style="{ top: top, left: left, position: 'absolute' }">
      <slot />
    </div>
  </transition>
</template>

<script>
import { rafThrottle } from '@/utils/throttle'
import { getHiddenElementSize, getRelativePosition, getScrollContainer } from '@/utils/dom'

export default {
  name: 'KcPopover',
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    appendToBody: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      left: '',
      top: ''
    }
  },
  watch: {
    visible: {
      immediate: true,
      handler(val) {
        this.$nextTick(() => {
          if (val) {
            this.showPopup()
          }
        })
      }
    }
  },
  mounted() {
    if (this.appendToBody) {
      document.body.appendChild(this.$el)
    }
    this._clickoutEvent = 'ontouchend' in document ? 'touchstart' : 'mousedown'
    document.addEventListener(this._clickoutEvent, this.handleClickOutside)
    // change the popup position when resize or scroll
    const relativeElement = this.$parent.$el
    this._showPopup = rafThrottle(() => this.showPopup())
    this._scrollContainer = getScrollContainer(relativeElement) || window
    this._scrollContainer.addEventListener('scroll', this._showPopup)
    window.addEventListener('resize', this._showPopup)
  },
  beforeDestroy() {
    if (this.appendToBody && this.$el.parentNode) {
      this.$el.parentNode.removeChild(this.$el)
    }
    document.removeEventListener(this._clickoutEvent, this.handleClickOutside)
    this._scrollContainer.removeEventListener('scroll', this._showPopup)
    window.removeEventListener('resize', this._showPopup)
  },
  methods: {
    handleClickOutside(ev) {
      if (!this.visible) return
      const { target } = ev
      const el = this.$el
      if (el && !el.contains(target)) {
        this.$emit('clickoutside', ev)
      }
    },
    showPopup() {
      if (!this.visible) return
      const popup = this.$el
      const relativeEle = this.$parent.$el
      const { appendToBody } = this
      if (!this._popupRect) {
        this._popupRect = getHiddenElementSize(popup)
      }
      const { width, height } = this._popupRect
      const { left, top } = getRelativePosition(relativeEle, width, height, appendToBody)
      this.left = left
      this.top = top
    }
  }
}
</script>

<style></style>
